package hhb.game.zhualaoer.core;

import hhb.game.zhualaoer.core.dao.*;
import hhb.game.zhualaoer.core.enums.*;
import hhb.game.zhualaoer.core.util.SessionUtil;
import jakarta.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;

@RestController
@RequestMapping("/zhualaoer")
@EnableScheduling
public class GameAction {

    private static final Logger logger = LoggerFactory.getLogger(GameAction.class);

    //假设这里有个用户列表
    private HashMap<String,User> logingUsers = new HashMap<String,User>();
    {
        logingUsers.put("666",new User("666","玩家1",1000));
        logingUsers.put("888",new User("888","玩家2",1000));
        logingUsers.put("999",new User("999","玩家3",1000));
    }

    //准备玩家数量
    private HashMap<String,User> readyUsers = new HashMap<String,User>();

    //牌库
    List<Card> deck = new ArrayList<>();

    //对局牌面信息
    private HashMap<String,GameInfo> gameInfos = new HashMap<String, GameInfo>();

    private GameStatus gameStatus = new GameStatus();

    //公牌
    List<Card> openCards ;

    //暗牌
    List<Card> darkCards;

    //当前回合出牌信息
    private HashMap<String,GameInfo> playAhandCards = new HashMap<String,GameInfo>();

    //全部出牌信息
    private ArrayList<Card> cardHands = new ArrayList<Card>();

    //当前回合玩家准备状态
    private HashMap<String,Integer> currentRoundUserState = new HashMap<String,Integer>();

    //登录
    @RequestMapping("/login")
    public Response login (HttpSession session,@RequestBody User user) {
        String userAccount = user.getUserAccount();
        if(userAccount == null || user.getUserAccount().isEmpty()){
            userAccount = SessionUtil.getCurrentUser(session);
        }
        //判断userAccount存在logingUsers中
        if(logingUsers.containsKey(userAccount)){
            //如果存在，则设置session属性
            SessionUtil.setLoggedInUser(session,userAccount);
            user = logingUsers.get(userAccount);
            return Response.success(user);
        }
        return  Response.fail(400, "用户不存在");
    }

    @RequestMapping("/ready")
    public Response play (HttpSession session) {
       if(!SessionUtil.isLoggedIn(session)){
           return Response.fail(500, "请登录");
       }
        String userAccount = SessionUtil.getCurrentUser(session);
        if(gameStatus.getStatus() == 2){
            return Response.fail(400, "游戏状态不正确");
        }
        //判断userAccount存在logingUsers中
        if(logingUsers.containsKey(userAccount)){
            logger.info("玩家{}准备",userAccount);
            //如果存在，则设置session属性
            SessionUtil.setLoggedInUser(session,userAccount);
            User user = logingUsers.get(userAccount);
            user.setStatus(EnumUserRedayStatus.REDAY.getValue());
            readyUsers.put(userAccount,user);
            gameStatus.setAllStatus(1,0,0);
            return Response.success(user);
        }
        return Response.fail(400, "用户不存在");
    }

    @RequestMapping("/reload")
    public String reload (String password) {
        if(password.equals("123456")){
            logger.info("重新初始化游戏状态");
            gameStatus.setAllStatus(0,0,0);
            //准备玩家清空
            readyUsers.clear();
            //已出牌信息清空
            cardHands.clear();
            //当前回合出牌信息清空
            playAhandCards.clear();
            //当前回合玩家准备状态清空
            currentRoundUserState.clear();
            //对局牌面信息清空
            gameInfos.clear();
        }
        return "ok";
    }

    //获取游戏对局信息
    @RequestMapping("/getGameStatus")
    public Response getGameStatus (HttpSession session) {
        if(!SessionUtil.isLoggedIn(session)){
            return Response.fail(500, "请登录");
        }
        return Response.success(gameStatus);
    }

    //获取游戏对局信息
    @RequestMapping("/getGameInfo")
    public Response getGameInfo (HttpSession session) {
        if(!SessionUtil.isLoggedIn(session)){
            return Response.fail(500, "请登录");
        }
        String userAccount = SessionUtil.getCurrentUser(session);
        if(gameInfos.containsKey(userAccount)){
            GameInfo gameInfo = gameInfos.get(userAccount);
            HashMap<String, Object> map = new HashMap<>();
            map.put("gameInfo",gameInfo);
            map.put("loginUser",logingUsers);
            return Response.success(map);
        }
        return Response.fail(400, "对局信息不存在");
    }

    /*
     * 出牌
     * cards是玩家出的2张牌
     */
    @RequestMapping("/playAhand")
    public Response playAhand (HttpSession session,@RequestBody ArrayList<Card> cards) {
        if(!SessionUtil.isLoggedIn(session)){
            return Response.fail(500, "请登录");
        }
        if (gameStatus.getStatus() != 2 && gameStatus.getRoundStatus() !=1){
            return Response.fail(400, "游戏状态不正确");
        }
        String userAccount = SessionUtil.getCurrentUser(session);
        //gameStatus 开始游戏后的第一个回合清空出牌记录
        int round = gameStatus.getRound();
        if(round < 5 && cards.size() != 2){
            return Response.fail(400, "出牌错误，请出2张牌");
        }else if(round == 5 &&  cards.size() != 3){
            return Response.fail(400, "出牌错误，第五回合需要出3张牌");
        }

        //获取当前玩家的手牌
        List<Card> handCards = gameInfos.get(userAccount).getHandCards();
        //判断cards存在handCards中
        for(Card card:cards){
            if(!handCards.contains(card)){
                return Response.fail(400, "出牌错误，你没有这张牌");
            }
        }

        if(playAhandCards.containsKey(userAccount)){
            GameInfo gameInfo = playAhandCards.get(userAccount);
            if(gameInfo.getRound() == round){
                return Response.fail(400, "不要重复出牌");
            }else{
                gameInfo = new GameInfo(round,logingUsers.get(userAccount),cards);
                playAhandCards.put(userAccount,gameInfo);
            }
        }else{
            playAhandCards.put(userAccount,new GameInfo(round,logingUsers.get(userAccount),cards));
        }
        logger.info("玩家{}出牌{}",userAccount,cards);
        return Response.success();
    }

    /**
     * 获取结算信息
     *
     */
    @RequestMapping("/getSett")
    public Response getSett(HttpSession session){
        if(!SessionUtil.isLoggedIn(session)){
            return Response.fail(500, "请登录");
        }
        HashMap<String, GameInfo> map = new HashMap<>();
        for(Map.Entry<String, GameInfo> entry :gameInfos.entrySet()){
            GameInfo gameInfo = new GameInfo();
            gameInfo.setRound(gameStatus.getRound());
            gameInfo.setResult(entry.getValue().getResult());
            gameInfo.setHandCards(playAhandCards.get(entry.getKey()).getHandCards());
            map.put(entry.getKey(),gameInfo);
        }
        return Response.success(map);
    }

   int nextRoundCoun = 0;
    /**
     * 下一回合
     */
    @RequestMapping("/nextRound")
    public Response nextRound(HttpSession session){
        if(!SessionUtil.isLoggedIn(session)){
            return Response.fail(400, "请登录");
        }
        if (gameStatus.getStatus() != 2 && gameStatus.getRoundStatus() == 3 ){
            return Response.fail(400, "游戏状态不正确");
        }
        String userAccount = SessionUtil.getCurrentUser(session);

        //判断是否有玩家未出牌
        if(currentRoundUserState.containsKey(userAccount)){
            if(currentRoundUserState.get(userAccount).equals(gameStatus.getRound()+1)){
                return Response.fail(400, "不要重复点击");
            }else if(currentRoundUserState.get(userAccount) > gameStatus.getRound()+1){
                return Response.fail(400, "回合状态错误");
            }
        }
        currentRoundUserState.put(userAccount,gameStatus.getRound()+1);

        return Response.success();
    }

    private void pk() {
        HashMap<String, GameInfo> map = new HashMap<>();
        Card card = darkCards.get(0);
        if(gameStatus.getRound() < 4){
            card = openCards.get(gameStatus.getRound()-1);

        }else if(gameStatus.getRound() == 4){
            card = darkCards.get(0);
        }
        // 存储每个玩家的 PokerHand 对象
        Map<String, PokerHand> playerHands = new HashMap<>();
        // 构建每个玩家的牌组
        for (Map.Entry<String, GameInfo> entry : playAhandCards.entrySet()) {
            String userAccount = entry.getKey();
            List<Card> handCards = entry.getValue().getHandCards();
            List<Card> allCards = new ArrayList<>(handCards);

            // 前四轮使用公共牌，最后一轮使用玩家手中的三张牌
            if (gameStatus.getRound() < 5) {
                allCards.add(card);
            }
            allCards.sort(Comparator.reverseOrder());
            logger.info("玩家{}PK手牌{}",userAccount,allCards);
            // 创建 PokerHand 对象
            PokerHand pokerHand = new PokerHand(allCards);
            playerHands.put(userAccount, pokerHand);
        }

        // 比较所有玩家的牌，找出第一名和第二名
        String firstPlayer = null;
        PokerHand firstHand = null;
        String secondPlayer = null;
        PokerHand secondHand = null;

        for (Map.Entry<String, PokerHand> entry : playerHands.entrySet()) {
            String currentPlayer = entry.getKey();
            PokerHand currentHand = entry.getValue();

            if (firstPlayer == null) {
                firstPlayer = currentPlayer;
                firstHand = currentHand;
            } else {
                int resultVsFirst = compareHands(currentHand, firstHand);
                if (resultVsFirst==1) {
                    // 当前玩家比第一名强，更新第一名和第二名
                    secondPlayer = firstPlayer;
                    secondHand = firstHand;
                    firstPlayer = currentPlayer;
                    firstHand = currentHand;
                } else {
                    // 当前玩家比第一名弱，检查是否比第二名强
                    if (secondPlayer == null) {
                        secondPlayer = currentPlayer;
                        secondHand = currentHand;
                    } else {
                        int resultVsSecond = compareHands(currentHand, secondHand);
                        if (resultVsSecond==1) {
                            secondPlayer = currentPlayer;
                            secondHand = currentHand;
                        }
                    }
                }
            }
        }
        logger.info("第一名{}，第二名{}",firstPlayer,secondPlayer);
        //更新用户积分和对局信息
        for (Map.Entry<String, User> entry : logingUsers.entrySet()) {
            GameInfo gameInfo = gameInfos.get(entry.getKey());
            HashMap<Integer, Integer> result = gameInfo.getResult();
            if(result == null || result.isEmpty()) {
                result = new HashMap<Integer, Integer>();
            }
            if(!entry.getKey().equals(secondPlayer)){
                User user = entry.getValue();
                user.setScore(user.getScore() + 10*gameStatus.getRound());
                entry.setValue(user);

                result.put(gameStatus.getRound(),1);
                gameInfo.setResult(result);
            }else {
                User user = entry.getValue();
                user.setScore(user.getScore() - (logingUsers.size()-1)*10*gameStatus.getRound());
                entry.setValue(user);

                result.put(gameStatus.getRound(),-1);
                gameInfo.setResult(result);
            }
        }
        gameStatus.setRoundStatus(3);
    }

    // 使用你提供的 compareHands 方法
    private static int compareHands(PokerHand hand1, PokerHand hand2) {
        int result = hand1.compareTo(hand2);
        if (result > 0) {
            return 1;
        } else if (result < 0) {
            return 2;
        } else {
            return 0;
        }
    }

    // 初始化牌库
    public void createDeck() {
        List<Card> create = new ArrayList<>();
        for (Suit suit : Suit.values()) {
            for (Rank rank : Rank.values()) {
                create.add(new Card(suit, rank));
            }
        }
        deck = create;
    }

    // 初始对局
    public void initGame() {
        //已出牌信息清空
        cardHands.clear();
        //当前回合出牌信息清空
        playAhandCards.clear();
        //当前回合玩家准备状态清空
        currentRoundUserState.clear();
        //创建
        createDeck();
        //洗牌
        Collections.shuffle(deck);
        //设置公牌-公开牌3张
        openCards = drawCards(deck, 3);

        //设置公牌-暗牌1张  暗牌到第4轮对局结算页面才显示。不返回给前台，防止作弊
        darkCards = drawCards(deck, 1);
        //给3个玩家发，每人发5张牌
        for(User user:readyUsers.values()) {
            List<Card> handCards = drawCards(deck, 5);
            gameInfos.put(user.getUserAccount(),new GameInfo(1,user,openCards,null,handCards));
        }
    }


    /**
     * 从牌库顶部抽取指定数量的牌
     * @param deck 当前牌库（将被修改）
     * @param numCards 要抽取的牌数
     * @return 抽取的牌列表（按发牌顺序）
     * @throws IllegalArgumentException 当牌库不足或参数非法时
     */
    public static List<Card> drawCards(List<Card> deck, int numCards) {
        // 1. 参数验证
//        if (numCards < 0) {
//            throw new IllegalArgumentException("发牌数量不能为负数");
//        }
//        if (deck == null || deck.isEmpty()) {
//            throw new IllegalArgumentException("牌库不能为空");
//        }

        // 2. 计算实际可发牌数
        int available = deck.size();
        int actualDraw = Math.min(numCards, available);

        // 3. 抽取牌并更新牌库
        List<Card> drawnCards = new ArrayList<>(deck.subList(0, actualDraw));
        deck.subList(0, actualDraw).clear();

        // 4. 洗牌控制（按需启用）
        // Collections.shuffle(drawnCards); // 如果需要随机发牌

        return drawnCards;
    }
    private void nextRoundGame(){
        for(Map.Entry<String, GameInfo> entry : gameInfos.entrySet()){
            //将出牌，从playAhandCards中获取，然后把GameINfo中的handCards更新，去掉出牌的牌。同时在给他发两张新的牌
            List<Card> handCards = entry.getValue().getHandCards();
            List<Card> playCards = playAhandCards.get(entry.getKey()).getHandCards();
            for(Card card:playCards){
                handCards.remove(card);
            }
            //更新回合
            entry.getValue().setRound(gameStatus.getRound());
            //第四回合更新暗牌
            if(gameStatus.getRound() == 4){
                entry.getValue().setDarkCards(darkCards);
            }
            //更新手牌
            if(gameStatus.getRound() < 5){
                handCards.addAll(drawCards(deck, 2));
            }
            entry.getValue().setHandCards(handCards);
        }
        //清空出牌记录
        playAhandCards.clear();
        gameStatus.setRoundStatus(1);
    }
    /**
     * 核心方法，用于定时执行一些任务
     * 这里模拟了一个定时任务，每隔1秒执行一次，并输出当前时间戳
     * 根据状态，去进行不同的操作
     */
    @Scheduled(fixedRate = 1000)
    public void fixedRateTask() {
        //全部准备，下回合开始
        int all = (int) currentRoundUserState.values().stream().filter(v -> v == gameStatus.getRound() + 1).count();
        logger.info("当前时间戳：{},游戏状态：{},当前回合：{},当前回合状态：{},准备玩家：{},当前出牌信息：{},下回合玩家准备状态：{}", System.currentTimeMillis(),
                gameStatus.getStatus(),gameStatus.getRound(), gameStatus.getRoundStatus(), readyUsers.size(), playAhandCards.size(), all);

        //1、全部玩家准备、开始发牌，游戏开始
        if (gameStatus.getStatus() == 1 && readyUsers.size() == 3){
            logger.info("全部准备就绪、开始初始化对局，游戏开始！");
            gameStatus.setAllStatus(2,1,1);
            initGame();
        }

        //2、对局中，当前回合状态是开始状态、玩家全部出牌。本回合结束
        if (gameStatus.getStatus() == 2 && gameStatus.getRoundStatus() == 1 && playAhandCards.size() == 3 ){

            logger.info("第{}回合,结算处理。本回合结束！",gameStatus.getRound());
            gameStatus.setRoundStatus(2);
            pk();
        }

        //3、对局中，当前回合状态结算完成、下回合玩家全部准备进行发牌
        if (gameStatus.getStatus() == 2 && gameStatus.getRound() < 5 && gameStatus.getRoundStatus() == 3 && all == 3 ){
            gameStatus.setRoundStatus(0);
            //改为下回合
            gameStatus.setRound( gameStatus.getRound()+1);
            logger.info("第{}回合,开始",gameStatus.getRound());
            nextRoundGame();
        }

        //4、对局中，第五回合结算完成、下回合玩家全部准备。重置游戏到新的对局
        if(gameStatus.getStatus() == 2 && gameStatus.getRound() == 5 && gameStatus.getRoundStatus() == 3 && all == 3 ){
            reload("123456");
        }

    }
}
